#include "ParticleSystemDecl.h"
#include "..\utils\Log.h"
#include "..\base\Engine.h"
#include "..\game\World.h"


namespace ds {

void ParticleAffectorDecl::create(ParticleSystem* particleSystem) {
	if ( m_AffectorType == AT_LIFE_TIME_AFFECTOR ) {
		float ttl = getData(0);
		particleSystem->addAffector(new LifetimeAffector(ttl));
	}
	else if ( m_AffectorType == AT_POSITION_AFFECTOR ) {
		particleSystem->addAffector(new PositionAffector());
	}
	else if ( m_AffectorType == AT_ROTATON_AFFECTOR ) {
		particleSystem->addAffector(new RotationAffector(m_Data[0]));
	}
	else if ( m_AffectorType == AT_ALPHA_AFFECTOR ) {
		particleSystem->addAffector(new AlphaAffector(m_Data[0],m_Data[1]));
	}
	else if ( m_AffectorType == AT_WIGGLE_AFFECTOR ) {
		particleSystem->addAffector(new WiggleAffector(m_Data[0],m_Data[1],m_Data[2]));
	}
	else if ( m_AffectorType == AT_COLOR_FADE_AFFECTOR ) {		
		particleSystem->addAffector(new ColorFadeAffector(m_Data[0],m_Data[1],m_Data[2],m_Data[3],m_Data[4],m_Data[5]));
	}
	else if ( m_AffectorType == AT_SIZE_AFFECTOR ) {
		particleSystem->addAffector(new SizeAffector(m_Data[0],m_Data[1]));
	}
	else if ( m_AffectorType == AT_SIZE_SINE_AFFECTOR ) {
		particleSystem->addAffector(new SizeSineAffector(m_Data[0],m_Data[1],m_Data[2]));
	}
	else if ( m_AffectorType == AT_RADIAL_VELOCITY_AFFECTOR ) {
		particleSystem->addAffector(new RadialVelocityAffector(m_Data[0],m_Data[1]));
	}
}


ParticleSystemDecl::~ParticleSystemDecl(void) {
	m_AffectorDeclarations.deleteContents();
}

ParticleSystem* ParticleSystemDecl::create() {
	ParticleSystem* ps = new ParticleSystem(m_Name);
	if ( m_EmitterType == ET_BOX ) {
		uint32 w = (uint32)size.x;
		uint32 h = (uint32)size.y;
		ps->setEmitter(new BoxEmitter(w,h,(uint32)total,textureRect,ttl,initialSize));
	}
	else if ( m_EmitterType == ET_POINT ) {
		ps->setEmitter(new PointEmitter((uint32)total,textureRect,ttl,initialSize,color,rotate));
	}
	else  if ( m_EmitterType == ET_RING ) {
		ps->setEmitter(new RingEmitter(radius,(uint32)total,textureRect,ttl,initialSize,color,rotate));
	}
	for ( uint32 i = 0; i < m_AffectorDeclarations.num(); ++i ) {
		ParticleAffectorDecl* dec = m_AffectorDeclarations[i];
		dec->create(ps);
	}
	return ps;
}

void ParticleSystemDecl::parseCategory(Category* root) {
	m_Name = root->getProperty("name");
	m_Texture = root->getProperty("texture");
	m_Layer = root->getProperty("layer");
	LOGC(logINFO,"ParticleSystemDecl") << "creating new particle system declaration name: " << m_Name;
	std::vector<Category*> categories = root->getChildren();
	for ( size_t i = 0; i < categories.size(); ++i ) {
		Category* cat = categories[i];
		if ( cat->getName() == "emitter" ) {
			std::string type = cat->getProperty("type");
			LOGC(logINFO,"ParticleSystemDecl") << "emitter type " << type;
			if ( type == "BoxEmitter" ) {
				m_EmitterType = ET_BOX;
			}
			else if ( type == "PointEmitter" ) {
				m_EmitterType = ET_POINT;
			}
			else if ( type == "RingEmitter" ) {
				m_EmitterType = ET_RING;
			}
			if ( cat->hasProperty("size") ) {
				size = cat->getVec2("size");
			}
			if ( cat->hasProperty("texture_rect") ) {
				textureRect = cat->getRect("texture_rect");
			}
			total = cat->read<int>("total",50);			
			ttl = cat->read<float>("ttl",2.0f);
			initialSize = cat->read<float>("initial_size",10.0f);
			color = Color(1.0f,1.0f,1.0f,1.0f);
			if ( cat->hasProperty("color") ) {
				color = cat->getColor("color");
			}
			rotate = cat->getBool("rotate",false);
			radius = cat->read<float>("radius",50.0f);
		}
		if ( cat->getName() == "affector" ) {
			if ( cat->hasProperty("type") ) {
				std::string type = cat->getProperty("type");
				ParticleAffectorDecl* affectorDecl = new ParticleAffectorDecl;
				LOGC(logINFO,"ParticleSystemDecl") << "affector found - type " << type;
				if ( type == "LifeTimeAffector" ) {
					affectorDecl->setAffectorType(AT_LIFE_TIME_AFFECTOR);
					affectorDecl->setData(0,cat->read<float>("ttl",2.0f));
				}				
				else if ( type == "PositionAffector" ) {
					affectorDecl->setAffectorType(AT_POSITION_AFFECTOR);
				}
				else if ( type == "RotationAffector" ) {
					affectorDecl->setAffectorType(AT_ROTATON_AFFECTOR);
					affectorDecl->setData(0,cat->read<float>("frequency",1.0f));
				}
				else if ( type == "AlphaAffector" ) {
					affectorDecl->setAffectorType(AT_ALPHA_AFFECTOR);
					affectorDecl->setData(0,cat->read<float>("min",1.0f));
					affectorDecl->setData(1,cat->read<float>("max",0.0f));
				}
				else if ( type == "WiggleAffector" ) {
					affectorDecl->setAffectorType(AT_WIGGLE_AFFECTOR);
					affectorDecl->setData(0,cat->read<float>("min",0.0f));
					affectorDecl->setData(1,cat->read<float>("max",0.0f));
					affectorDecl->setData(2,cat->read<float>("amplitude",1.0f));
				}
				else if ( type == "ColorFadeAffector" ) {
					affectorDecl->setAffectorType(AT_COLOR_FADE_AFFECTOR);
					Vec2 r = cat->getVec2("r");
					Vec2 g = cat->getVec2("g");
					Vec2 b = cat->getVec2("b");
					affectorDecl->setData(0,r.x);
					affectorDecl->setData(1,r.y);
					affectorDecl->setData(2,g.x);
					affectorDecl->setData(3,g.y);
					affectorDecl->setData(4,b.x);
					affectorDecl->setData(5,b.y);
				}
				else if ( type == "SizeAffector" ) {
					affectorDecl->setAffectorType(AT_SIZE_AFFECTOR);
					affectorDecl->setData(0,cat->read<float>("min",1.0f));
					affectorDecl->setData(1,cat->read<float>("max",0.0f));
				}
				else if ( type == "RadialVelocityAffector" ) {
					affectorDecl->setAffectorType(AT_RADIAL_VELOCITY_AFFECTOR);
					affectorDecl->setData(0,cat->read<float>("velocity",1.0f));
					affectorDecl->setData(1,cat->read<float>("velocity_diff",0.0f));					
				}
				else if ( type == "SizeSineAffector" ) {
					affectorDecl->setAffectorType(AT_SIZE_SINE_AFFECTOR);
					affectorDecl->setData(0,cat->read<float>("min",1.0f));
					affectorDecl->setData(1,cat->read<float>("multiplier",1.0f));
					affectorDecl->setData(2,cat->read<float>("amplitude",1.0f));
				}
				m_AffectorDeclarations.append(affectorDecl);
			}				
			else {
				LOGC(logERROR,"ParticleSystemDecl") << "missing type property detected";
			}
		}
	}
}

void ParticleSystemDeclParser::createResource(ResourceDeclaration* declaration) {
	ParticleManager* pm = static_cast<ParticleManager*>(gEngine->getWorld().getNode("Particles"));
	if ( pm == 0 ) {
		LOGC(logINFO,"ParticleSystemDecl") << "no node found yet - creating new node";
		ParticleManager* pm = new ParticleManager("Particles",m_Texture,m_Layer.c_str());
		gEngine->getWorld().attachNode(pm,m_Layer.c_str());
	}
}

ResourceDeclaration* ParticleSystemDeclParser::loadTextFile(const ResourceFile& resourceFile) {
	PlainTextReader reader;
	if ( reader.readFile(resourceFile.fqName.c_str()) ) {
		LOGC(logINFO,"ParticleSystemDecl") << "reading particle system file";
		Category* root = reader.getRoot();
		std::string psName = root->getProperty("name");
		ParticleSystemDecl* decl = new ParticleSystemDecl(psName);
		m_Texture = root->getProperty("texture");
		m_Layer = root->getProperty("layer");
		decl->parseCategory(root);		
		return decl;	
	}
	return 0;
}

}
